package com.tanger.auth.provider;

import com.tanger.auth.mapper.AuthMapper;
import com.tanger.common.enums.EnumIsAble;
import com.tanger.common.enums.EnumYesNo;
import com.tanger.common.exception.ServiceException;
import com.tanger.common.redis.RedisUtil;
import com.tanger.common.vo.UserDetail;
import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AccountStatusException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.provider.*;
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

/**
 * 手机号密码登录
 */
public class PasswordTokenGranter extends AbstractTokenGranter {
   private final AuthMapper authMapper;
   private final RedisUtil redisUtils;
   private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

   public PasswordTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService,
                               OAuth2RequestFactory requestFactory, AuthMapper authMapper, RedisUtil redisUtils) {
      this(tokenServices, clientDetailsService, requestFactory, authMapper, redisUtils, "password");
   }

   protected PasswordTokenGranter(AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService,
                                  OAuth2RequestFactory requestFactory, AuthMapper authMapper, RedisUtil redisUtils, String grantType) {
      super(tokenServices, clientDetailsService, requestFactory, grantType);
      this.authMapper = authMapper;
      this.redisUtils = redisUtils;
   }

   protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {
      Map<String, String> parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());
      String username = (String) parameters.get("username");
      String password =(String) parameters.get("password");
      //String roletype = (String) parameters.get("roletype");
      Authentication userAuth = null;

      try {
         UserDetail user = authMapper.queryUserInfoByPhone(username);

         if (user == null) {
            throw new ServiceException(String.format("找不到此手机号%s。", username));
         }
         if (user.getStatus().equals(EnumIsAble.no.getValue())){
            throw new ServiceException("账户已停用，请联系超级管理员");
         }
         if (user.getDelFlag().equals(EnumYesNo.yes.getValue())){
            throw new ServiceException("账户不存在或已删除，请联系超级管理员确认");
         }

         List<String> roleCodeList = new ArrayList<String>();
         //TODO 无角色信息,只存在权限问题
         UserDetails userDetails = new User(
                 user.getName(), user.getPassword(), AuthorityUtils.createAuthorityList(roleCodeList.toArray(new String[] {})));
         if(!encoder.matches(password, userDetails.getPassword())){
            throw new ServiceException("密码错误");
         }
         parameters.put("id", user.getId().toString());
         parameters.put("name", user.getName().toString());
         parameters.put("phone", user.getMobile().toString());
         parameters.put("roleType", "");
         userAuth = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
         ((AbstractAuthenticationToken) userAuth).setDetails(parameters);

      } catch (AccountStatusException var11) {
         throw new ServiceException(var11.toString());
      } catch (BadCredentialsException var12) {
         throw new ServiceException(var12.toString());
      }

      if (!userAuth.isAuthenticated()) {
         throw new ServiceException("The account password could not be verified: " + username);
      } else {
         OAuth2Request storedOAuth2Request = this.getRequestFactory().createOAuth2Request(client, tokenRequest);
         return new OAuth2Authentication(storedOAuth2Request, userAuth);
      }
   }
}
